﻿//*** Guidance generated code ***//
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Net.Mime;
using System.Text;
using System.Web;
using System.Web.Mvc;

using ProjectBase.Core;
using ProjectBase.Core.Web;

namespace ProjectBase.Mvc.Views
{
    public class StreamResult : ActionResult
    {
        #region constructor
        public StreamResult() { }

        /// <summary>
        ///     Returns FileResult with provided name, type and based on XDocument
        /// </summary>
        /// <param name = "model">Model with all needed information</param>
        public StreamResult(IExportModel model)
        {
            Contract.Requires(model.Is(), " Sorry, model was null, cannot proceed ");
            Contract.Requires(model.DataReader.Is(), " DataReader is null. Cannot proceed to send FileResult ");
            Model = model;
        }
        #endregion constructor

        #region public
        /// <summary>
        ///     MVC key point method, which provides the output to the client
        /// </summary>
        /// <param name = "context"></param>
        public override void ExecuteResult(ControllerContext context)
        {
            if (context.IsNull())
            {
                return;
            }
            ProcessModel();

            var response = context.HttpContext.Response;

            response.Clear();
            response.ClearContent();

            response.ContentType = MediaTypeNames.Text.Plain;
            if (ContentType.IsNotEmpty())
            {
                response.ContentType = ContentType;
            }

            response.ContentEncoding = ContentEncoding ?? Encoding.Default;

            if (FileName.IsNotEmpty())
            {
                response.AppendHeader("content-disposition", "attachment; filename=" + FileName);
            }

            if (Headers.Is())
            {
                foreach (var header in Headers)
                {
                    response.AppendHeader(header.Key, header.Value);
                }
            }

            var builder = new StringBuilder();

            // HEAD
            BuildHeader(builder);

            // ROWS
            builder = BuildRows(response, builder);

            response.BinaryWrite(ToBuffer(builder));
            response.Flush();

            DataReader.Close();
            DataReader.Dispose();
        }
        #endregion public

        #region protected output builders
        /// <summary>
        ///     Process the model and assigns inner properties
        /// </summary>
        void ProcessModel()
        {
            if (Model.IsNull())
            {
                return;
            }
            var extension = Model.FileExtension.Is()
                                ? (Model.FileExtension.StartsWith(".", StringComparison.OrdinalIgnoreCase)
                                       ? string.Empty
                                       : ".") + Model.FileExtension
                                : string.Empty;
            FileName = Model.FileName
                       + DateTime.Now.GetHashCode()
                       + extension;
            ContentType = Model.ContentType;
            ContentEncoding = Model.Encoding;
            DataReader = Model.DataReader;
            ColumnSeparator = Model.ColumnSeparator;
        }

        StringBuilder BuildRows(HttpResponseBase response, StringBuilder builder)
        {
            var recCount = 0;
            while (DataReader.Read())
            {
                for (var i = 0; i < DataReader.FieldCount; i++)
                {
                    // if an entry is not null
                    if (!Convert.IsDBNull(DataReader.GetValue(i)))
                    {
                        builder.Append(Convert.ToString(DataReader.GetValue(i)));
                    }
                    if (i < DataReader.FieldCount - 1)
                    {
                        builder.Append(ColumnSeparator);
                    }
                }
                builder.Append("\n");

                if (recCount++ <= 500)
                {
                    continue;
                }
                response.BinaryWrite(ToBuffer(builder));
                response.Flush();

                recCount = 0;
                builder = new StringBuilder();
            }
            return builder;
        }

        void BuildHeader(StringBuilder builder)
        {
            for (var i = 0; i < DataReader.FieldCount; i++)
            {
                builder.Append(DataReader.GetName(i));
                if (i < DataReader.FieldCount - 1)
                {
                    builder.Append(ColumnSeparator);
                }
            }
            builder.Append("\n");
        }

        protected virtual byte[] ToBuffer(StringBuilder sb)
        {
            return new UTF8Encoding()
                .GetBytes(sb.ToString().ToCharArray())
                .ToArray();
        }
        #endregion protected output builders

        #region properties
        public IExportModel Model { get; set; }

        public virtual IDataReader DataReader { get; set; }
        public virtual string ColumnSeparator { get; set; }

        /// <summary>
        ///     Name for client
        /// </summary>
        public virtual string FileName { get; set; }

        /// <summary>
        ///     Crucial Encoding with
        /// </summary>
        public virtual Encoding ContentEncoding { get; set; }

        /// <summary>
        ///     Helps browsers to decide but extension is usually more important
        /// </summary>
        public virtual string ContentType { get; set; }

        /// <summary>
        ///     Header information
        /// </summary>
        public virtual IDictionary<string, string> Headers { get; set; }
        #endregion properties
    }
}